#include <chrono>
#include <string>

#include "xap_data_center.h"

#define RTK_UDP_SERVER_PORT 8899
#define BUFF_LEN 128
#define RTK_UDP_SERVER_IP "192.168.3.10"

int client_fd = -1;
struct sockaddr_in ser_addr;

void XnetMessageCallBack(void* context, xag_nav::os::Xap2Frame& xap2_frame,
                         uint16_t error_code);

navos_sdk::XagFlymapAppData * navos_sdk::XagFlymapAppData::_instance = 0;

navos_sdk::XagFlymapAppData::XagFlymapAppData()
{
    m_flymap_app_data_thread = NULL;
}

void navos_sdk::XagFlymapAppData::initilize()
{
    if (NULL == m_flymap_app_data_thread) {
        m_flymap_app_data_thread = new Thread(this, upload_flymap_app_data_cb);
        if (NULL == m_flymap_app_data_thread) {
            printf("XagFlymapAppData::init create upload flymap data failed.\n");
        }
    }
}

int navos_sdk::XagFlymapAppData::initilize(int flag)
{
	using xag_nav::os::Application;
	using xag_nav::os::Regist_t;

	// 应用初始化
    Regist_t regist{};
    regist.ip = "192.168.234.1";
    regist.port = 6380;
    regist.pkg_name = "com.xa.app.a311d.flymap_app.app";
    regist.app_name = "flymap_app";
	regist.version_name = "6.2.0.38";
	regist.version_code = 38;
    if (Application::Instance()->init(regist) < 0) {
        SPDLOG_INFO("Application registration failed");
        return -1;
    }

	return 0;
}

int navos_sdk::XagFlymapAppData::initilize(char flag)
{
	using xag_nav::os::Application;
	using xag_nav::os::Regist_t;

	// 应用初始化
    Regist_t regist{};
    regist.ip = "192.168.234.1";
    regist.port = 6380;
    regist.pkg_name = "com.xa.app.a311d.flymap_app.app";
    regist.app_name = "flymap_app";
	regist.version_name = "6.2.0.36";
	regist.version_code = 36;

    if (Application::Instance()->init(regist) < 0) {
        SPDLOG_INFO("Application registration failed");
        return -1;
    }
	else {
		SPDLOG_INFO("Application registration successfuly");
	}

	if (NULL == m_flymap_app_data_thread) {
        m_flymap_app_data_thread = new Thread(this, upload_flymap_app_data_cb);
        if (NULL == m_flymap_app_data_thread) {
            printf("XagFlymapAppData::init create upload flymap data failed.\n");
        }
    }

	udp_init();

	return 0;
}


void *navos_sdk::XagFlymapAppData::upload_flymap_app_data_cb(void * p)
{
    XagFlymapAppData * pobjXap_flymap = (XagFlymapAppData *) p;
    if (NULL == p)
        return (void *) 0;

    pobjXap_flymap->process(0);

    return (void *) 0;
}

int navos_sdk::XagFlymapAppData::xap_upload_to_datacenter(char * ptype, char * pdata, unsigned short len)
{
	using xag_nav::os::Application;
    using std::string;

	// 缓存数据中心
    auto storage = Application::Instance()->createStorage();
    // 持久数据中心
    auto storage_persist = Application::Instance()->createStoragePersist();

    // 统一以 string 储存
    {
        string content(pdata);
        storage->setUserData(ptype, const_cast<char*>(content.c_str()),
                             content.size());
        storage_persist->setUserData(ptype, const_cast<char*>(content.c_str()),
                                     content.size());
    }

	printf("%%%%%%%%%%%% [upload]:[%s] ---> [%s] %%%%%%%%%%%%\n", ptype, pdata);

	// 读取
	{
		char buff[1024]{0};
		// 需要传入 buff 大小
		long long buff_len = sizeof(buff);

		// 判断 key 是否存在
		if (storage->isUserKeyExist("CurrentStatus")) {
			storage->getUserData("CurrentStatus", buff, buff_len);
			// 传出的是写入长度
			SPDLOG_INFO("CurrentStatus : {}, len : {}", buff, buff_len);
		} else {
			SPDLOG_ERROR("CurrentStatus not exist!");
		}

		// 清空数据
		bzero(buff, sizeof(buff));
		// 重新载入大小
		buff_len = sizeof(buff);

		if (storage_persist->isUserKeyExist("CurrentStatus")) {
			storage_persist->getUserData("CurrentStatus", buff, buff_len);
			SPDLOG_INFO("CurrentStatus : {}, len : {}", buff, buff_len);
		} else {
			SPDLOG_ERROR("CurrentStatus not exist!");
		}
	}

	return 0;
}

void invoke_flymap_upload_data()
{
	printf("============= ft xap2.0 initilize =============\n");
	//navos_sdk::XagFlymapAppData::instance()->initilize(); 
	//navos_sdk::XagFlymapAppData::instance()->initilize(0); 
	navos_sdk::XagFlymapAppData::instance()->initilize('e'); 
}

void invoke_xap_upload_to_datacenter(char * ptype, char * pdata, unsigned short len)
{
	printf("============= ft xap2.0 upload =============\n");
	navos_sdk::XagFlymapAppData::instance()->xap_upload_to_datacenter(ptype, pdata, len);
}

bool navos_sdk::XagFlymapAppData::process()
{
    return 0;
}

bool navos_sdk::XagFlymapAppData::process(int flag)
{
  using std::string;
  int ac = -1;

  using xag_nav::os::Application;
  using xag_nav::os::DataEncoding;
  using xag_nav::os::FrameType;
  using xag_nav::os::Regist_t;
  using xag_nav::os::Xap2Frame;
  using xag_nav::os::content;

  using xag_nav::os::utils::TypeUtil;

	Xap2Frame xap2_frame;
	content xap2_content;
	uint32_t timeout = 300;

  // 服务初始化
  auto xnet_service = Application::Instance()->createService("router-rtk");

  // 最好判定获取的指针是否为空,否者后续会引发段错误
  if (xnet_service == nullptr) {
    SPDLOG_ERROR("Failed to create service!");
    return -1;
  }

  // 配置服务的接收回调
  {  // 设置接收消息回调
    xnet_service->msgCallBack(
        std::bind(&XnetMessageCallBack, std::placeholders::_1,
                  std::placeholders::_2, std::placeholders::_3));
  }

    char sendBuff[] = {
        0xf8, // f8
        0x45, // version[7-6] + cmd:[5:0]
        0x01, // request_id
        0x00, // respond_id
        0x01, // from_node
        0x00,
        0x55,
        0x00,
        0x01, // to_node        01:controller 03:rtk
        0x00,
        0x03,
        0x00,
        0x09, // length
        0x00,
        0x00, // timeout
        0x00, // reserve
        /* other protocol split line */
        0x0a, // cmd
        0x01,
        0x00,
        0x03,
        0x00,	/* to/from */
		0x00,
		0x00,
		0x00,
		0x0B,
    };

	//以下都是 xap2 帧内容必须填入的选项
	// 超时时间
	xap2_frame.setTimeout(timeout);

	// data 编码方式
	xap2_frame.setDataEncoding(
	static_cast<uint32_t>(DataEncoding::EN_BINARY));

	// 设置 xap 2.0 中对应的 dataProtocol
	// 1-5000 统一编址(0x0001 - 0x1388)
	// 5000-10000 为用户自定义编址(0x1389 - 0x2710)
	// 通过 XAP2 Content 中的的 from 与 dataProtocol
	// 确认 Content 中 data 唯一对应的 .proto 文件
	xap2_frame.setDataProtocol(0x2000);

	// date
    xap2_frame.setData((const char *)sendBuff, sizeof(sendBuff));

	while (1) {
		// 发送消息
		ac = xnet_service->sendMsg("ROUTER", xap2_frame);

		// 延时
		//std::this_thread::sleep_for(std::chrono::seconds(1));
		usleep(500000);

		printf("============= ft event ac = %d =============\n", ac);
	}

  return 0;
}

void navos_sdk::XagFlymapAppData::subscribe_rtk(void)
{

}

// 消息回调
void XnetMessageCallBack(void* context, xag_nav::os::Xap2Frame& xap2_frame,
                         uint16_t error_code) 
{
	int i = 0;
	unsigned char buf[BUFF_LEN] = {0};

#if 0
	SPDLOG_INFO("This is a message, form {}, to {}.", xap2_frame.from(),
														xap2_frame.to());
	SPDLOG_INFO("error_code : {}", error_code);
	SPDLOG_INFO("sequence : {}", xap2_frame.sequence());
	SPDLOG_INFO("timestamp : {}", xap2_frame.timestamp());
	SPDLOG_INFO("timeout : {}", xap2_frame.timeout());

	printf("============= ft event XnetMessageCallBack =============\n");
#endif

	SPDLOG_INFO("beeee ------\n");
	for (i = 0; i < xap2_frame.data().length(); i++) {
		//std::cout << "0x"  << ' ' << std::hex << static_cast<unsigned char> (xap2_frame.data().at(i));
		printf("%.2x ",xap2_frame.data().at(i));
		buf[i] = xap2_frame.data().at(i);
	}

	udp_msg_sender_hex(client_fd, (struct sockaddr*)&ser_addr, buf);

	printf("enddd ------\n");
}

void udp_msg_sender_hex(int fd, struct sockaddr* dst, unsigned char * buf)
{
    socklen_t len;
	int i = 0;
	
	len = sizeof(*dst);	
	for (i = 0; i < BUFF_LEN; i++) {
		printf("%.2x ", buf[i]);
	}
	sendto(fd, buf, BUFF_LEN, 0, dst, len);
	printf("\n============= udp_msg_sender_hex =============\n");
}

/*
    client:
            socket-->sendto-->revcfrom-->close
*/

int udp_init(void)
{
	sleep(10);

    client_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(client_fd < 0)
    {
        printf("create socket fail!\n");
        return -1;
    }

    memset(&ser_addr, 0, sizeof(ser_addr));
    ser_addr.sin_family = AF_INET;
    ser_addr.sin_addr.s_addr = inet_addr(RTK_UDP_SERVER_IP);
    ser_addr.sin_port = htons(RTK_UDP_SERVER_PORT); 

    //close(client_fd);

    return 0;
}


